Project

In diesem Projekt wird eine Explorative Datenanalyse von Automobilen durchgeführt.
Als Datengrundlage dient die Webseite Autoscout24 (https://www.autoscout24.de/), eine Online-Plattform zum Kauf und Verkauf von Neu- und Gebrauchtwagen.
Autoscout24 Startseite
Autoscout24 Suche
Ziel ist es, die Daten verschiedener Fahrzeuge zu vergleichen und daraus mögliche Schlüsse auf Korrelation der Daten zu ziehen. So soll beispielsweise analysiert werden, welche Fahrzeugeigentschaften einen Einfluss auf dessen Verkaufspreis haben.
Eine weitere interessante Fragestellung ist der Zusammenhang zwischen Kraftstoffart und Verbrauchsdaten.
Die im Projekt getätigten Analysen und Vergleiche verschiedener Fahrzeuge sollen zudem als Kaufentscheidung eines Fahrzeugs dienen.

Import

Zunächst wreden alle für dieses Projekt benötigten Packages und Bibliothen importiert.

#Basics
import pandas as pd
import numpy as np

#Webcrawling
#pip install beautifulsoup4
from bs4 import BeautifulSoup
import requests

#Deactivate warnings
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
#Data visualization
import matplotlib.pyplot as plt

import plotly.express as px
import plotly.graph_objs as go
import plotly.io as pio
import plotly.figure_factory as ff
import plotly.offline as pyo
# Set notebook mode to work in offline
pyo.init_notebook_mode()

#np.set_printoptions(precision=6)
#np.set_printoptions(suppress=True)

import seaborn as sns 
#Geo visualization
import folium
#!pip install geopy
from geopy.geocoders import Nominatim

Webcrawling & Creation of Dataframe

Als Erstes ist es notwendig, die Fahrzeugdaten von der Webseite Autoscout24 zu crawlen und in einem Dataframe zu speichern.

Für das Crawlen der Daten wird die Methode extractPageCarDF definiert. Dieser muss beim Aufruf die Variable URL mitgegeben werden. Dabei handelt es sich um den Link zu einem Autoscout24 Suchergebnis, welches stehts 20 Autos beinhaltet (sofern sie den Suchkriterien entsprechen).
Jedes Auto wird dabei vom HTML Element Article umschlossen. Daher wird eine Schleife implementiert, welche für jedes Auto im Suchergebnis die nachfolgenden Daten aus den dazugehörigen HTML Elementen der Webseite extrahiert:

  • Titel

  • Fahrzeugversion

  • Untertitel

  • Preis

  • Leasingpreis

  • Fahrzeugstandort

Falls eines der HTML-Elemente nicht gefunden werden kann, wird jede der Anweisungen durch einen try except Block umschlossen. Falls kein Eintrag gefunden wird, wird der jeweilige Wert mit einem NULL-Wert belegt.

Eine Besonderheit ist zudem der Preis. Wird das Element ListItem_pricerow gefunden, handelt es sich um einen Verkaufspreis und kein Leasingangebot. Leasing wird daher False gesetzt. Wird dieses Element nicht gefunden, sondern LeasingPrice_price handelt es sich um ein Leasing Angebot.

Diese Daten werden dem Dataframe pageCarDF hinzugefügt.

In einer weiteren Schleife werden die folgenden Fahrzeugdetaildaten aus dem HTML Div Container VehicleDetailTable abgezogen:
Autoscout24 VehicleDetailTable
Es wird zunächst ein leeres Dataframe initialisiert. In einer Schleife wird für jedes Fahrzeug die leere Liste VehicleDetailList erzeugt und dieser in einer inneren Schleife jedes Element der VehicleDetailTable hinzugefügt.
Die Liste wird anschließend dem VehicleDetailDF hinzugefügt. Hierfür ist ein try except notwendig. Leasing Fahrzeuge haben ein zweites Element namens VehicleDetailTable, welches allerdings nur 3 Einträge zum Themengebiet Leasing hat. Der Versuch diese Listen mit 3 Einträgen dem VehicleDetailDF hinzuzufügen, läuft aufgrund nicht passender Längen auf Fehler. Dieser Fehler wird im except Block bewusst mit einem Continue abgefangen. Die Leasing VehicleDetailLists werden nicht weiter benötigt und fallen somit raus.

Nun liegt das pageCarDF und das VehicleDetailDF vor, welche beide je Fahrzeug eine Zeile beinhalten.
Die beiden Dataframes werden mithilfe der merge-Methode über den Index gejoined.

Die Methode gibt das Dataframe pageCarDF als return value zurück. Diese beinhaltet alle relevanten Daten von den Fahrzeugen einer Suchergebnisseite (in der Regel 20 Fahrzeuge).

def extractPageCarDF(URL):

    soup=BeautifulSoup(requests.get(URL).text,"html.parser")
    pageCarDF=pd.DataFrame()

    for car in soup.findAll("article"):
        data = car.find("div", {"class": lambda L: L and L.startswith("ListItem_wrapper")})
        try:
            header = data.find("h2").text
        except:
            header = np.NaN
        try:
            version = data.find("span", {"class": lambda L: L and L.startswith("ListItem_version")}).text
        except:
            version = np.NaN
        try:
            subtitle = data.find("span", {"class": lambda L: L and L.startswith("ListItem_subtitle")}).text
        except:
            subtitle = np.NaN
        try:
            #Versuch Preis Element zu finden
            price = data.find("div", {"class": lambda L: L and L.startswith("ListItem_pricerow")}).text
            leasing = False
        except:
            #wenn oberes Element nicht gefunden werden kann, handelt es sich um einen Leasing Wagen, mit dem nachfolgenden HTML Element
            price = data.find("span", {"class": lambda L: L and L.startswith("LeasingPrice_price")}).text
            leasing = True 

        try:
            location = car.find("span", {"style": lambda L: L and L.startswith("grid-area:address")}).text
        except:
            location = np.NaN

        #Daten dem pageCarDF hinzufügen
        pageCarDF = pageCarDF.append({"Titel":header, "Version":version, "Untertitel":subtitle, "Preis":price, "Leasing":leasing, "Standort":location}, ignore_index=True)


    #VehicleDetailTable
    VehicleDetailDF = pd.DataFrame()
    for car in soup.findAll("div" , {"class":"VehicleDetailTable_container__mUUbY"}):
        VehicleDetailList = []
        for c in car:
            VehicleDetailList.append(c.text)
        try:
            VehicleDetailDF = VehicleDetailDF.append({"km":VehicleDetailList[0], "Erstzulassung":VehicleDetailList[1], "PS":VehicleDetailList[2], "Zustand":VehicleDetailList[3], "Fahrzeughalter":VehicleDetailList[4], "Getriebe":VehicleDetailList[5], "Kraftstoff": VehicleDetailList[6], "Verbrauch_l_pro_100km":VehicleDetailList[7], "Emissionen_g_pro_km":VehicleDetailList[8]}, ignore_index=True)
        except:
            continue #VehicleDetailLists mit Länge 3 sind extra VehicleDetailTables, die nur bei Leasing Wagen vorkommen. Diese sollen nicht übernommen werden, daher Continue
    
    #Join pageCarDF und VehicleDetailDF
    pageCarDF = pd.merge(pageCarDF, VehicleDetailDF, left_index=True, right_index=True)   

    return pageCarDF

Die Methode extractPageCarDF gilt es nun mit den passenden Paramentern aufzurufen.

Es werden zunächst zwei leere Dataframes initialisiert.
Die Suche auf Autoscout24 wurde zunächst komplett ohne Filter aufgerufen. Pro Suchergebnis gibt die Webseite ingesamt 20 Suchergebnisseiten mit jeweils 20 Fahrzeugen aus. Somit können mit einer Suche maximal 20 * 20 = 400 Autos von der Webseite gecrawlt werden.
Da für die Analysen im Projekt mehr als 400 Datensätze gewünscht sind, wird ein Filter “Erstzulassung bis” gesetzt. Die Jahreszahlen werden in der Liste fregtoList von 1990 bis 2022 in 2er Schritten gewählt.

In einer Schleife wird zunächst der Filter auf die jeweilige Jahreszahl gesetzt. In einer inneren Schleife werden jeweils die 20 Seiten des Suchergebnisses gecrawlt.
Dafür wird zunächst die URL aus “Erstzulassung bis” fregto= und Suchergebnisseite page erstellt. Die URL wird an die Methode extractPageCarDF übergeben und diese ausgeführt.
Das resultierende Dataframe pageCarDF mit 20 Einträgen wird dem Dataframe AutoDFraw angehängt. Anschließend wird die Methode für die nächste Seite um Suchergebnis ausgeführt und das Ergebnis wieder AutoDFraw hinzufügt.
Dataframe pageCarDF wird somit bei jeder Ausführung der Methode extractPageCarDF neu erstellt, während Dataframe AutoDFraw immer weiter wächst.

Die Methode wird für jeden Filter “Erstzulassung bis” für 20 Suchergebnisseiten ausgeführt, sodass das Dataframe AutoDFraw am Ende über 6000 Einträge enhält.

AutoDFraw=pd.DataFrame()
pageCarDF=pd.DataFrame()
baselink = "https://www.autoscout24.de/lst?fregto="
fregtoList = list(range(1995, 2022, 1))
#fregfromList = list(range(1991, 2021, 2))
#fregfromList.insert(0, 1900)

for freg in fregtoList:
    for page in range(20):
        URL = baselink + str(freg) + "&page=" + str(page)
        pageCarDF = extractPageCarDF(URL)
        AutoDFraw=pd.concat([AutoDFraw, pageCarDF],axis=0, ignore_index=True)
AutoDFraw
Titel Version Untertitel Preis Leasing Standort km Erstzulassung PS Zustand Fahrzeughalter Getriebe Kraftstoff Verbrauch_l_pro_100km Emissionen_g_pro_km
0 Lincoln Town Car Signature Series Prins Gasanlage Voll NaN € 4.900,-Keine Angabe 0.0 Funda Aktas • DE-12107 Berlin 277.711 km 10/1993 157 kW (213 PS) Gebraucht 2 Fahrzeughalter Automatik Autogas (LPG) - (l/100 km) - (g/km)
1 Mercedes-Benz 200 HECKFLOSSE W110 DAIMLER BENZ NaN € 14.870,-Keine Angabe 0.0 Norbert Lindemann • DE-12305 Berlin 39.526 km 12/1965 70 kW (95 PS) Gebraucht - (Fahrzeughalter) Schaltgetriebe Benzin - (l/100 km) - (g/km)
2 Land Rover Discovery 2.5 Base TDI NaN € 3.990,- 0.0 Contáctanos en: • ES-17800 OLOT 214.446 km 05/1992 82 kW (111 PS) Gebraucht - (Fahrzeughalter) Schaltgetriebe Diesel 8,9 l/100 km (komb.) - (g/km)
3 MG MGB GT aus 1. Hand, original 53.000 KM NaN € 25.900,-Keine Angabe 0.0 Britta Mirbach • DE-22297 Hamburg 53.372 km 07/1975 98 kW (133 PS) Gebraucht 1 Fahrzeughalter Schaltgetriebe - (Kraftstoff) - (l/100 km) - (g/km)
4 Mercedes-Benz 220 S Ponton W180 Oldtimer H-Kennz. fahrbereit NaN € 22.950,-Keine Angabe 0.0 DE-92318 Neumarkt 54.900 km 01/1957 74 kW (101 PS) Gebraucht - (Fahrzeughalter) Schaltgetriebe Benzin - (l/100 km) 0 g/km (komb.)
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
10268 Skoda Superb Combi 2.0TDI Active AHK Sitzheizung Anhängerkupplung, Armlehne, Sitzheizung, Dachr... € 22.840,-Sehr guter Preis 0.0 Ihr Verkaufsteam Nürnberg • DE-90441 Nürnberg 56.800 km 11/2019 110 kW (150 PS) Gebraucht 1 Fahrzeughalter Schaltgetriebe Diesel - (l/100 km) - (g/km)
10269 BMW Z4 sDrive20i Sport Steptronic Xenon Leder SHZ Sportfahrwerk, Sportpaket, Sportsitze, Einpark... € 22.990,-Guter Preis 0.0 Carlo Jesse • DE-49477 Ibbenbüren 85.300 km 10/2012 135 kW (184 PS) Gebraucht 2 Fahrzeughalter Automatik Benzin 6,8 l/100 km (komb.) 161 g/km (komb.)
10270 Audi A3 2,0 Cabriolet Ambition S-line+Sitzheizung+Tagf... Mitsubishi & Honda Vertragspartner seit 40 Jahren € 14.880,-Sehr guter Preis 0.0 - - • DE-41061 Mönchengladbach 68.335 km 04/2012 147 kW (200 PS) Gebraucht 3 Fahrzeughalter Schaltgetriebe Benzin 7,2 l/100 km (komb.) 171 g/km (komb.)
10271 Honda CR-V 2,0 i-VTEC Comfort Leder+Allrad+Multif.Lenkrad... Allrad, Zentralverriegelung, Lederlenkrad, Kat... € 14.280,-Sehr guter Preis 0.0 - - • DE-41747 Viersen 56.105 km 05/2012 110 kW (150 PS) Gebraucht 1 Fahrzeughalter Automatik Benzin 8,4 l/100 km (komb.) 195 g/km (komb.)
10272 Hyundai i30 1.6 Turbo GDI Turbo Zentralverriegelung, Tempomat, Lichtsensor, Tr... € 13.290,-Sehr guter Preis 0.0 Kevin Schuster • DE-85276 Pfaffenhofen 103.882 km 02/2016 137 kW (186 PS) Gebraucht 2 Fahrzeughalter Schaltgetriebe Benzin 7,3 l/100 km (komb.) 173 g/km (komb.)

10273 rows × 15 columns

Raw Data Transformation

Die Fahrzeugdaten von Autoscout24 wurden erfolgreich abgezogen und in einem Dataframe gespeichert. Allerdings entsprechen viele Spalten noch nicht dem gewünschten Format, da beispielsweise Sonderzeichen enthalten sind oder numerische Werte nicht also solche erkannt werden.
Aus diesem Grund muss das Dataframe nun so bearbeitet werden, dass alle Spalten in einer für die Explorative Datenanalyse sinnvollen Struktur vorliegen.

Zunächst werden die Rohdaten in einer Excel Tabelle gespeichert. So kann jederzeit auf die Rohdaten zurückgegriffen werden und auch das Ergebnis der Datentransformation nachvollzogen werden.

AutoDFraw.to_excel("AutoDF_vor_Replace.xlsx")

Anschließend wird das Dataframe AutoDF mit den Rohdaten initialisiert.

AutoDF= AutoDFraw

Eine für die Datenanalyse interessante Information ist die Automarke. Diese ist im Titel der Anzeige als erstes Wort enthalten. Daher wird zur Bestimmung der Automarke das erste Wort der Spalte Titel extrahiert und in einer neuen Spalte Marke gespeichert.

AutoDF['Marke'] = AutoDF['Titel'].str.split('\s+').str[0]

Im nächsten Schritt wird das Dataframe um störende oder überflüssige Character bereinigt. Dazu gehören störende Satzzeichen, Währungen, Strings, etc.

Da in einzelnen Fällen Leasingpreise noch hinter Kaufpreisen angezeigt werden, müssen zuerst alle Zeichen hinter dem ersten Kaufpreis entfernt werden. Dann werden in der nächsten Codezeile alle weiteren nicht numerischen Zeichen entfernt.

AutoDF['Preis'] = AutoDF['Preis'].replace('(,-).*', '',regex=True)
AutoDF['Preis'] = AutoDF['Preis'].str.replace(r'[^0-9]+', '')

Die nachfolgenden Spalten enthalten im Datensatz noch Einheiten. Diese sind bereits im Spaltentitel vorhanden und werden somit aus den Datensätzen entfernt, sodass nur noch numerische Werte verbleiben.

AutoDF['km'] = AutoDF['km'].replace(r'[^0-9]+', '',regex=True)
AutoDF['Fahrzeughalter'] = AutoDF['Fahrzeughalter'].replace(r'[^0-9]+', '',regex=True)
AutoDF['Verbrauch_l_pro_100km'] = AutoDF['Verbrauch_l_pro_100km'].replace(['\(l/100 km\)', 'l/100 km','\(komb.\)'], '',regex=True)
AutoDF['Emissionen_g_pro_km'] = AutoDF['Emissionen_g_pro_km'].replace(r'[^0-9]+', '',regex=True)

Der Monat der Erstzulassung wird entfernt sowie alle übrigbleibenden nicht numerischen Zeichen.

AutoDF['Erstzulassung'] = AutoDF['Erstzulassung'].replace('.*/', '',regex=True)
AutoDF['Erstzulassung'] = AutoDF['Erstzulassung'].replace(r'[^0-9]+', '',regex=True)

Bei der PS-Angabe muss zuerst der Wert in kW entfernt werden, danach alle weiteren nicht numerischen Zeichen.

AutoDF['PS'] = AutoDF['PS'].replace(['.*kW','\(','PS\)'], '',regex=True)
AutoDF['PS'] = AutoDF['PS'].replace(r'[^0-9]+', '',regex=True)

Oli check hier den Text nochmal bitte

Bei der Bereinigung fehlender Werte tritt das Problem auf, dass bei den Attributen Verbrauch und Emissionen fehlende Werte bei Elektroautos = 0 bedeuten, bei nicht Elektroautos jedoch tatsächlich fehlende Werte.

Da bei Verbrauch und Emissionen von Nutzern teilweise keine Werte angegeben werden, werden alle fehlenden Werte durch NULL ersetzt, damit diese später ausgewertet werden können.

AutoDF['Verbrauch_l_pro_100km'] = AutoDF['Verbrauch_l_pro_100km'].replace(['-','','0'], np.NaN,regex=True)
AutoDF['Emissionen_g_pro_km'] = AutoDF['Emissionen_g_pro_km'].replace(['-','','0'], np.NaN,regex=True)
AutoDF['Fahrzeughalter'] = AutoDF['Fahrzeughalter'].replace(['-',''], np.NaN,regex=True)
AutoDF['Erstzulassung'] = AutoDF['Erstzulassung'].replace('', np.NaN,regex=True)
AutoDF['km'] = AutoDF['km'].replace('', np.NaN,regex=True)
AutoDF['PS'] = AutoDF['PS'].replace('', np.NaN,regex=True)

# da keine Angabe bei Verbrauch und Emissionen bei Elektroautos korrekt sein kann, wird der Wert wieder durch 0 ersetzt
AutoDF.loc[AutoDF.Kraftstoff == 'Elektro', 'Verbrauch_l_pro_100km'] = 0
AutoDF.loc[AutoDF.Kraftstoff == 'Elektro', 'Emissionen_g_pro_km'] = 0

AutoDF
Titel Version Untertitel Preis Leasing Standort km Erstzulassung PS Zustand Fahrzeughalter Getriebe Kraftstoff Verbrauch_l_pro_100km Emissionen_g_pro_km Marke
0 Lincoln Town Car Signature Series Prins Gasanlage Voll NaN 4900 0.0 Funda Aktas • DE-12107 Berlin 277711 1993 213 Gebraucht 2 Automatik Autogas (LPG) NaN NaN Lincoln
1 Mercedes-Benz 200 HECKFLOSSE W110 DAIMLER BENZ NaN 14870 0.0 Norbert Lindemann • DE-12305 Berlin 39526 1965 95 Gebraucht NaN Schaltgetriebe Benzin NaN NaN Mercedes-Benz
2 Land Rover Discovery 2.5 Base TDI NaN 3990 0.0 Contáctanos en: • ES-17800 OLOT 214446 1992 111 Gebraucht NaN Schaltgetriebe Diesel 8,9 NaN Land
3 MG MGB GT aus 1. Hand, original 53.000 KM NaN 25900 0.0 Britta Mirbach • DE-22297 Hamburg 53372 1975 133 Gebraucht 1 Schaltgetriebe - (Kraftstoff) NaN NaN MG
4 Mercedes-Benz 220 S Ponton W180 Oldtimer H-Kennz. fahrbereit NaN 22950 0.0 DE-92318 Neumarkt 54900 1957 101 Gebraucht NaN Schaltgetriebe Benzin NaN NaN Mercedes-Benz
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
10268 Skoda Superb Combi 2.0TDI Active AHK Sitzheizung Anhängerkupplung, Armlehne, Sitzheizung, Dachr... 22840 0.0 Ihr Verkaufsteam Nürnberg • DE-90441 Nürnberg 56800 2019 150 Gebraucht 1 Schaltgetriebe Diesel NaN NaN Skoda
10269 BMW Z4 sDrive20i Sport Steptronic Xenon Leder SHZ Sportfahrwerk, Sportpaket, Sportsitze, Einpark... 22990 0.0 Carlo Jesse • DE-49477 Ibbenbüren 85300 2012 184 Gebraucht 2 Automatik Benzin 6,8 161 BMW
10270 Audi A3 2,0 Cabriolet Ambition S-line+Sitzheizung+Tagf... Mitsubishi & Honda Vertragspartner seit 40 Jahren 14880 0.0 - - • DE-41061 Mönchengladbach 68335 2012 200 Gebraucht 3 Schaltgetriebe Benzin 7,2 171 Audi
10271 Honda CR-V 2,0 i-VTEC Comfort Leder+Allrad+Multif.Lenkrad... Allrad, Zentralverriegelung, Lederlenkrad, Kat... 14280 0.0 - - • DE-41747 Viersen 56105 2012 150 Gebraucht 1 Automatik Benzin 8,4 195 Honda
10272 Hyundai i30 1.6 Turbo GDI Turbo Zentralverriegelung, Tempomat, Lichtsensor, Tr... 13290 0.0 Kevin Schuster • DE-85276 Pfaffenhofen 103882 2016 186 Gebraucht 2 Schaltgetriebe Benzin 7,3 173 Hyundai

10273 rows × 16 columns

In der spalte Verbrauch_l_pro_100km wird das Komma zur Dezimaltrennung durch einen Punkt ersetzt.

AutoDF['Verbrauch_l_pro_100km'] = AutoDF['Verbrauch_l_pro_100km'].replace(',', '.',regex=True)

Die Spalte Standort wird aufgeteilt in die Spalten PLZ, Stadt und Land.
Das letzte Wort der Spalte Standort ist immer der Stadtname.
Die Postleitzahl kann extrahiert werden, indem alle nicht numerischen Zeichen entfernt werden.
Land und PLZ werden durch einen Bindestrich getrennt. Daher kann der Bindestrich zum Split verwendet werden, wobei der erste Teil weiterverwendet wird. Dieser wird nochmal mit durch Leerzeichen getrennt und hiervon der letzte Teil als Land gespeichert.

#Stadtname
AutoDF['Stadt'] = AutoDF['Standort'].str.split(' ').str[-1]

#PLZ
AutoDF['PLZ'] = AutoDF['Standort'].replace(r'[^0-9]+', '',regex=True)

#Land
AutoDF['Land'] = AutoDF['Standort'].str.split('-').str[-2].str.split(' ').str[-1]

AutoDF
Titel Version Untertitel Preis Leasing Standort km Erstzulassung PS Zustand Fahrzeughalter Getriebe Kraftstoff Verbrauch_l_pro_100km Emissionen_g_pro_km Marke Stadt PLZ Land
0 Lincoln Town Car Signature Series Prins Gasanlage Voll NaN 4900 0.0 Funda Aktas • DE-12107 Berlin 277711 1993 213 Gebraucht 2 Automatik Autogas (LPG) NaN NaN Lincoln Berlin 12107 DE
1 Mercedes-Benz 200 HECKFLOSSE W110 DAIMLER BENZ NaN 14870 0.0 Norbert Lindemann • DE-12305 Berlin 39526 1965 95 Gebraucht NaN Schaltgetriebe Benzin NaN NaN Mercedes-Benz Berlin 12305 DE
2 Land Rover Discovery 2.5 Base TDI NaN 3990 0.0 Contáctanos en: • ES-17800 OLOT 214446 1992 111 Gebraucht NaN Schaltgetriebe Diesel 8.9 NaN Land OLOT 17800 ES
3 MG MGB GT aus 1. Hand, original 53.000 KM NaN 25900 0.0 Britta Mirbach • DE-22297 Hamburg 53372 1975 133 Gebraucht 1 Schaltgetriebe - (Kraftstoff) NaN NaN MG Hamburg 22297 DE
4 Mercedes-Benz 220 S Ponton W180 Oldtimer H-Kennz. fahrbereit NaN 22950 0.0 DE-92318 Neumarkt 54900 1957 101 Gebraucht NaN Schaltgetriebe Benzin NaN NaN Mercedes-Benz Neumarkt 92318 DE
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
10268 Skoda Superb Combi 2.0TDI Active AHK Sitzheizung Anhängerkupplung, Armlehne, Sitzheizung, Dachr... 22840 0.0 Ihr Verkaufsteam Nürnberg • DE-90441 Nürnberg 56800 2019 150 Gebraucht 1 Schaltgetriebe Diesel NaN NaN Skoda Nürnberg 90441 DE
10269 BMW Z4 sDrive20i Sport Steptronic Xenon Leder SHZ Sportfahrwerk, Sportpaket, Sportsitze, Einpark... 22990 0.0 Carlo Jesse • DE-49477 Ibbenbüren 85300 2012 184 Gebraucht 2 Automatik Benzin 6.8 161 BMW Ibbenbüren 49477 DE
10270 Audi A3 2,0 Cabriolet Ambition S-line+Sitzheizung+Tagf... Mitsubishi & Honda Vertragspartner seit 40 Jahren 14880 0.0 - - • DE-41061 Mönchengladbach 68335 2012 200 Gebraucht 3 Schaltgetriebe Benzin 7.2 171 Audi Mönchengladbach 41061 DE
10271 Honda CR-V 2,0 i-VTEC Comfort Leder+Allrad+Multif.Lenkrad... Allrad, Zentralverriegelung, Lederlenkrad, Kat... 14280 0.0 - - • DE-41747 Viersen 56105 2012 150 Gebraucht 1 Automatik Benzin 8.4 195 Honda Viersen 41747 DE
10272 Hyundai i30 1.6 Turbo GDI Turbo Zentralverriegelung, Tempomat, Lichtsensor, Tr... 13290 0.0 Kevin Schuster • DE-85276 Pfaffenhofen 103882 2016 186 Gebraucht 2 Schaltgetriebe Benzin 7.3 173 Hyundai Pfaffenhofen 85276 DE

10273 rows × 19 columns

Spalte Standort wird nicht weiter benötigt und kann entfernt werden.

AutoDF = AutoDF.drop('Standort', axis=1)

In der Spalte Untertitel werden Ausstattungsmerkmale des Fahrzeugs aufgezählt. Einige ausgewählte Austattungsmerkmale werden als extra Spalten in das Dataframe aufgenommen.
Dafür wird folgende Annahme getroffen:
Ein Fahrzeug besitzt eine bestimmte Ausstattung, wenn diese in Spalte Untertitel erwähnt wird. Wird diese dort nicht erwähnt, besitzt ein Fahrzeug diese Ausstattung nicht.
Dies wird mithilfe der Methode str.contains geprüft.

AutoDF['Alufelgen']= AutoDF['Untertitel'].str.contains("Alufelgen")
AutoDF['Sitzheizung']= AutoDF['Untertitel'].str.contains("Sitzheizung")
AutoDF['Klimaanlage']= (AutoDF['Untertitel'].str.contains("Klimaanlage")) | (AutoDF['Untertitel'].str.contains("Klimaautomatik"))
AutoDF['Einparkhilfe']= AutoDF['Untertitel'].str.contains("Einparkhilfe ")
AutoDF['Navigationssystem']= AutoDF['Untertitel'].str.contains("Navigationssystem")
AutoDF
Titel Version Untertitel Preis Leasing km Erstzulassung PS Zustand Fahrzeughalter ... Emissionen_g_pro_km Marke Stadt PLZ Land Alufelgen Sitzheizung Klimaanlage Einparkhilfe Navigationssystem
0 Lincoln Town Car Signature Series Prins Gasanlage Voll NaN 4900 0.0 277711 1993 213 Gebraucht 2 ... NaN Lincoln Berlin 12107 DE NaN NaN False NaN NaN
1 Mercedes-Benz 200 HECKFLOSSE W110 DAIMLER BENZ NaN 14870 0.0 39526 1965 95 Gebraucht NaN ... NaN Mercedes-Benz Berlin 12305 DE NaN NaN False NaN NaN
2 Land Rover Discovery 2.5 Base TDI NaN 3990 0.0 214446 1992 111 Gebraucht NaN ... NaN Land OLOT 17800 ES NaN NaN False NaN NaN
3 MG MGB GT aus 1. Hand, original 53.000 KM NaN 25900 0.0 53372 1975 133 Gebraucht 1 ... NaN MG Hamburg 22297 DE NaN NaN False NaN NaN
4 Mercedes-Benz 220 S Ponton W180 Oldtimer H-Kennz. fahrbereit NaN 22950 0.0 54900 1957 101 Gebraucht NaN ... NaN Mercedes-Benz Neumarkt 92318 DE NaN NaN False NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
10268 Skoda Superb Combi 2.0TDI Active AHK Sitzheizung Anhängerkupplung, Armlehne, Sitzheizung, Dachr... 22840 0.0 56800 2019 150 Gebraucht 1 ... NaN Skoda Nürnberg 90441 DE False True False False False
10269 BMW Z4 sDrive20i Sport Steptronic Xenon Leder SHZ Sportfahrwerk, Sportpaket, Sportsitze, Einpark... 22990 0.0 85300 2012 184 Gebraucht 2 ... 161 BMW Ibbenbüren 49477 DE False True False True False
10270 Audi A3 2,0 Cabriolet Ambition S-line+Sitzheizung+Tagf... Mitsubishi & Honda Vertragspartner seit 40 Jahren 14880 0.0 68335 2012 200 Gebraucht 3 ... 171 Audi Mönchengladbach 41061 DE False False False False False
10271 Honda CR-V 2,0 i-VTEC Comfort Leder+Allrad+Multif.Lenkrad... Allrad, Zentralverriegelung, Lederlenkrad, Kat... 14280 0.0 56105 2012 150 Gebraucht 1 ... 195 Honda Viersen 41747 DE True False False False False
10272 Hyundai i30 1.6 Turbo GDI Turbo Zentralverriegelung, Tempomat, Lichtsensor, Tr... 13290 0.0 103882 2016 186 Gebraucht 2 ... 173 Hyundai Pfaffenhofen 85276 DE False True True False False

10273 rows × 23 columns

Abgesehen von Klimaanlage entstehen None Values in den neu erzeugten Ausstattungsspalten wenn die Spalte Untertitel None ist, daher werden diese nun durch False ersetzt. Dafür wird davon ausgegangen, dass ein Fahrzeug bspw. keine Alufelgen hat, wenn keine Beschreibung unter Untertitel angegeben ist.

AutoDF['Alufelgen'] = AutoDF['Alufelgen'].replace(np.NaN, False)
AutoDF['Sitzheizung'] = AutoDF['Sitzheizung'].replace(np.NaN, False)
AutoDF['Einparkhilfe'] = AutoDF['Einparkhilfe'].replace(np.NaN, False)
AutoDF['Navigationssystem'] = AutoDF['Navigationssystem'].replace(np.NaN, False)
AutoDF
Titel Version Untertitel Preis Leasing km Erstzulassung PS Zustand Fahrzeughalter ... Emissionen_g_pro_km Marke Stadt PLZ Land Alufelgen Sitzheizung Klimaanlage Einparkhilfe Navigationssystem
0 Lincoln Town Car Signature Series Prins Gasanlage Voll NaN 4900 0.0 277711 1993 213 Gebraucht 2 ... NaN Lincoln Berlin 12107 DE False False False False False
1 Mercedes-Benz 200 HECKFLOSSE W110 DAIMLER BENZ NaN 14870 0.0 39526 1965 95 Gebraucht NaN ... NaN Mercedes-Benz Berlin 12305 DE False False False False False
2 Land Rover Discovery 2.5 Base TDI NaN 3990 0.0 214446 1992 111 Gebraucht NaN ... NaN Land OLOT 17800 ES False False False False False
3 MG MGB GT aus 1. Hand, original 53.000 KM NaN 25900 0.0 53372 1975 133 Gebraucht 1 ... NaN MG Hamburg 22297 DE False False False False False
4 Mercedes-Benz 220 S Ponton W180 Oldtimer H-Kennz. fahrbereit NaN 22950 0.0 54900 1957 101 Gebraucht NaN ... NaN Mercedes-Benz Neumarkt 92318 DE False False False False False
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
10268 Skoda Superb Combi 2.0TDI Active AHK Sitzheizung Anhängerkupplung, Armlehne, Sitzheizung, Dachr... 22840 0.0 56800 2019 150 Gebraucht 1 ... NaN Skoda Nürnberg 90441 DE False True False False False
10269 BMW Z4 sDrive20i Sport Steptronic Xenon Leder SHZ Sportfahrwerk, Sportpaket, Sportsitze, Einpark... 22990 0.0 85300 2012 184 Gebraucht 2 ... 161 BMW Ibbenbüren 49477 DE False True False True False
10270 Audi A3 2,0 Cabriolet Ambition S-line+Sitzheizung+Tagf... Mitsubishi & Honda Vertragspartner seit 40 Jahren 14880 0.0 68335 2012 200 Gebraucht 3 ... 171 Audi Mönchengladbach 41061 DE False False False False False
10271 Honda CR-V 2,0 i-VTEC Comfort Leder+Allrad+Multif.Lenkrad... Allrad, Zentralverriegelung, Lederlenkrad, Kat... 14280 0.0 56105 2012 150 Gebraucht 1 ... 195 Honda Viersen 41747 DE True False False False False
10272 Hyundai i30 1.6 Turbo GDI Turbo Zentralverriegelung, Tempomat, Lichtsensor, Tr... 13290 0.0 103882 2016 186 Gebraucht 2 ... 173 Hyundai Pfaffenhofen 85276 DE False True True False False

10273 rows × 23 columns

In der Spalte Leasing werden die Werte noch mit 0.0 für False und 1.0 für True ausgegeben. Dies wird in Boolean Werte geändert.

AutoDF['Leasing'] = AutoDF['Leasing'].replace(0.0, False)
AutoDF['Leasing'] = AutoDF['Leasing'].replace(1.0, True)

Mit der .info() Methode werden nun alle Spalten des Dataframes mit deren Datentypen angezeigt.

AutoDF.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10273 entries, 0 to 10272
Data columns (total 23 columns):
 #   Column                 Non-Null Count  Dtype 
---  ------                 --------------  ----- 
 0   Titel                  10273 non-null  object
 1   Version                10273 non-null  object
 2   Untertitel             5613 non-null   object
 3   Preis                  10273 non-null  object
 4   Leasing                10273 non-null  bool  
 5   km                     10273 non-null  object
 6   Erstzulassung          10273 non-null  object
 7   PS                     9828 non-null   object
 8   Zustand                10273 non-null  object
 9   Fahrzeughalter         4983 non-null   object
 10  Getriebe               10273 non-null  object
 11  Kraftstoff             10273 non-null  object
 12  Verbrauch_l_pro_100km  5422 non-null   object
 13  Emissionen_g_pro_km    3770 non-null   object
 14  Marke                  10273 non-null  object
 15  Stadt                  10099 non-null  object
 16  PLZ                    10099 non-null  object
 17  Land                   10099 non-null  object
 18  Alufelgen              10273 non-null  bool  
 19  Sitzheizung            10273 non-null  bool  
 20  Klimaanlage            10273 non-null  bool  
 21  Einparkhilfe           10273 non-null  bool  
 22  Navigationssystem      10273 non-null  bool  
dtypes: bool(6), object(17)
memory usage: 1.4+ MB

Das Dataframe hat 22 Spalten. Davon haben die meisten den Datentyp object, obwohl es sich bei einigen davon um numerische Werte handelt. Dies muss noch geändert werden. Lediglich die Boolean Spalten wie beispielsweise Leasing wurden korrekt identifiziert.
Die meisten Spalten haben keine NULL Werte. Allerdings exisitieren auch Spalten, die sehr viele NULL-Werte aufweisen. Beispielsweise Emissionen_g_pro_km.
Nachfolgend werden die NULL-Werte in einer heatmap visuaisiert.

sns.set_theme(style="ticks", color_codes=True)

# Identifizieren der NULL Werte via Heatmap
sns.heatmap(AutoDF.isnull(), 
            yticklabels=False,
            cbar=False, 
            cmap='viridis');
_images/Projekt_47_0.png

In der Heatmap ist zu erkennen, dass sehr viele NULL-Werte in den Spalten Untertitel, Fahrzeughalter, Verbrauch_l_pro_100km und Emissionen_g_pro_km exisitieren.
Nachfolgend werden hierfür nochmal die exakten Mengen ausgegeben:

print(AutoDF.isnull().sum())
Titel                       0
Version                     0
Untertitel               4660
Preis                       0
Leasing                     0
km                          0
Erstzulassung               0
PS                        445
Zustand                     0
Fahrzeughalter           5290
Getriebe                    0
Kraftstoff                  0
Verbrauch_l_pro_100km    4851
Emissionen_g_pro_km      6503
Marke                       0
Stadt                     174
PLZ                       174
Land                      174
Alufelgen                   0
Sitzheizung                 0
Klimaanlage                 0
Einparkhilfe                0
Navigationssystem           0
dtype: int64

Die Spalten Verbrauch_l_pro_100km und Emissionen_g_pro_km weisen viele NULL-Werte auf. Für die Analyse sind diese jedoch von großer Bedeutung. Zeilen mit fehlenden Abgas- oder Verbrauchswerten bzw. fehlenden Kilometer und PS-Angaben werden daher gelöscht.

noch mehr Begründung, warum wir Null Werte löschen?

AutoDF = AutoDF[AutoDF['Verbrauch_l_pro_100km'].notna()]
AutoDF = AutoDF[AutoDF['Emissionen_g_pro_km'].notna()]
AutoDF = AutoDF[AutoDF['km'].notna()]
AutoDF = AutoDF[AutoDF['PS'].notna()]
print(AutoDF.isnull().sum())
Titel                       0
Version                     0
Untertitel                636
Preis                       0
Leasing                     0
km                          0
Erstzulassung               0
PS                          0
Zustand                     0
Fahrzeughalter           1034
Getriebe                    0
Kraftstoff                  0
Verbrauch_l_pro_100km       0
Emissionen_g_pro_km         0
Marke                       0
Stadt                     122
PLZ                       122
Land                      122
Alufelgen                   0
Sitzheizung                 0
Klimaanlage                 0
Einparkhilfe                0
Navigationssystem           0
dtype: int64

Als nächstes werden die Datentypen angepasst, indem numerische Spalten einer Datentypkonvertierung unterzogen werden.

AutoDF['Preis'] = AutoDF['Preis'].astype('int')
AutoDF['km'] = AutoDF['km'].astype('int')
AutoDF['PS'] = AutoDF['PS'].astype('int')
AutoDF['Emissionen_g_pro_km'] = AutoDF['Emissionen_g_pro_km'].astype('int')
AutoDF['Erstzulassung'] = AutoDF['Erstzulassung'].astype('float')
AutoDF['Verbrauch_l_pro_100km'] = AutoDF['Verbrauch_l_pro_100km'].astype('float')

Die Spalten Zustand, Getriebe, Kraftstoff Marke und Land weisen jeweils nur eine geringe Menge verschiedener Ausprägungen vor. Daher werden diese Spalten im Typ categorical abgespeichert. Alle übrigen Spalten verbleiben als object.

AutoDF['Zustand'] = AutoDF['Zustand'].astype('category')
AutoDF['Getriebe'] = AutoDF['Getriebe'].astype('category')
AutoDF['Kraftstoff'] = AutoDF['Kraftstoff'].astype('category')
AutoDF['Marke'] = AutoDF['Marke'].astype('category')
AutoDF['Land'] = AutoDF['Land'].astype('category')
AutoDF.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 3337 entries, 21 to 10272
Data columns (total 23 columns):
 #   Column                 Non-Null Count  Dtype   
---  ------                 --------------  -----   
 0   Titel                  3337 non-null   object  
 1   Version                3337 non-null   object  
 2   Untertitel             2701 non-null   object  
 3   Preis                  3337 non-null   int32   
 4   Leasing                3337 non-null   bool    
 5   km                     3337 non-null   int32   
 6   Erstzulassung          3337 non-null   float64 
 7   PS                     3337 non-null   int32   
 8   Zustand                3337 non-null   category
 9   Fahrzeughalter         2303 non-null   object  
 10  Getriebe               3337 non-null   category
 11  Kraftstoff             3337 non-null   category
 12  Verbrauch_l_pro_100km  3337 non-null   float64 
 13  Emissionen_g_pro_km    3337 non-null   int32   
 14  Marke                  3337 non-null   category
 15  Stadt                  3215 non-null   object  
 16  PLZ                    3215 non-null   object  
 17  Land                   3215 non-null   category
 18  Alufelgen              3337 non-null   bool    
 19  Sitzheizung            3337 non-null   bool    
 20  Klimaanlage            3337 non-null   bool    
 21  Einparkhilfe           3337 non-null   bool    
 22  Navigationssystem      3337 non-null   bool    
dtypes: bool(6), category(5), float64(2), int32(4), object(6)
memory usage: 325.1+ KB

Descriptive Statistics

Nachfolgend werden alle numerischen Features in einer Liste gespeichert.

num_features=AutoDF.select_dtypes(include=np.number).columns.to_list()
num_features
['Preis',
 'km',
 'Erstzulassung',
 'PS',
 'Verbrauch_l_pro_100km',
 'Emissionen_g_pro_km']

Gleiches wird für alle nicht numerischen Features durchgeführt.

cat_features=AutoDF.select_dtypes(exclude=np.number).columns.to_list()
cat_features
['Titel',
 'Version',
 'Untertitel',
 'Leasing',
 'Zustand',
 'Fahrzeughalter',
 'Getriebe',
 'Kraftstoff',
 'Marke',
 'Stadt',
 'PLZ',
 'Land',
 'Alufelgen',
 'Sitzheizung',
 'Klimaanlage',
 'Einparkhilfe',
 'Navigationssystem']

Für einen ersten Überblick über die Datenverteilung numerischer Features bietet sich die describe() Methode an. Diese gibt für jede Spalte die Anzahl, Durchschnitt, Standardabweichung, Minimum, Maximum sowie die Quartile an.

AutoDF.describe().transpose()
count mean std min 25% 50% 75% max
Preis 3337.0 25348.575667 25826.283777 219.0 11330.0 18890.0 28950.0 239990.0
km 3337.0 99516.753671 63420.382807 900.0 50704.0 86835.0 137087.0 425000.0
Erstzulassung 3337.0 2008.643093 9.119443 1950.0 2004.0 2011.0 2015.0 2021.0
PS 3337.0 224.735091 115.791800 18.0 140.0 190.0 290.0 706.0
Verbrauch_l_pro_100km 3337.0 7.994996 2.912554 0.0 6.0 7.3 9.4 21.1
Emissionen_g_pro_km 3337.0 193.681450 69.525198 0.0 147.0 178.0 225.0 488.0

Alle Features haben einen Count von 3337, da dies der Anzahl der Datenpunkt entspricht.

Werte ändern sich hier jetzt mit jeder Ausführung. Müssen irgendwann einen Stand safen und den diskutieren

Nachfolgend wird die Anzahl der unique values je Feature ausgegeben.

for col in AutoDF.columns:
    values = AutoDF[col].unique()
    print(col, "has", len(AutoDF[col].unique()), "unique values")
Titel has 300 unique values
Version has 683 unique values
Untertitel has 568 unique values
Preis has 488 unique values
Leasing has 2 unique values
km has 606 unique values
Erstzulassung has 35 unique values
PS has 160 unique values
Zustand has 1 unique values
Fahrzeughalter has 9 unique values
Getriebe has 3 unique values
Kraftstoff has 6 unique values
Verbrauch_l_pro_100km has 108 unique values
Emissionen_g_pro_km has 172 unique values
Marke has 41 unique values
Stadt has 228 unique values
PLZ has 268 unique values
Land has 20 unique values
Alufelgen has 2 unique values
Sitzheizung has 2 unique values
Klimaanlage has 2 unique values
Einparkhilfe has 2 unique values
Navigationssystem has 2 unique values

Beschreiben, was wir da sehen

Als nächstes wird die Anzahl der Fahrzeuge pro Kraftstoffart ausgegeben.

print(AutoDF['Kraftstoff'].value_counts())
Benzin            2425
Diesel             850
Elektro/Benzin      42
Autogas (LPG)       14
Elektro/Diesel       4
Elektro              2
Name: Kraftstoff, dtype: int64

Die häufigste Kraftstoffart mit xxx Fahrzeugen ist Benzin, gefolgt von Diesel.
Alle anderen Kraftstoffarten kommen in Relation zur Gesamtmenge an Fahrzeugen eher selten vor.

Ebenso interessant ist die Anzahl der Fahrzeuge pro Getriebeart.

print(AutoDF['Getriebe'].value_counts())
Automatik         1772
Schaltgetriebe    1530
Halbautomatik       35
Name: Getriebe, dtype: int64

Automatik und Schaltgetriebe kommen ungefähr gleich oft vor. Halbautomatikfahrzeuge kommen dagegen eher selten vor.

Nachfolgend wird der prozentuale Anteil jeder Automarke in Bezug auf die Gesamtmasse aller Fahrzeuge ausgegeben.

print(AutoDF['Marke'].value_counts(normalize=True))
Mercedes-Benz    0.166916
BMW              0.166317
Audi             0.165418
Volkswagen       0.118070
Porsche          0.061432
Opel             0.046149
Ford             0.036260
Jaguar           0.031166
Volvo            0.019778
Renault          0.019179
MINI             0.018580
Citroen          0.013785
Fiat             0.012286
Alfa             0.009589
Skoda            0.009290
Honda            0.008990
Toyota           0.008990
Aston            0.008391
Hyundai          0.008391
Kia              0.008091
SEAT             0.008091
Mitsubishi       0.006293
Mazda            0.005993
SsangYong        0.004795
Sonstige         0.004795
Saab             0.004795
Dodge            0.004795
Nissan           0.003596
Peugeot          0.003296
MG               0.002397
Alpina           0.002397
Suzuki           0.002098
Cadillac         0.002098
Lexus            0.001798
Cupra            0.001498
Ferrari          0.001199
Subaru           0.000899
Chevrolet        0.000899
smart            0.000599
Land             0.000300
Jeep             0.000300
Name: Marke, dtype: float64

Die häufigste auf Autoscout24 angebotene Automarke ist Mercedes-Benz (16,69%), dicht gefolgt von von BMW (16,63%) und Audi (16,54%).
Die drei seltensten Automarken sind Smart (0,05%), Land (0,03%) und Jeep (0,03%).

AutoDF.hist(bins=20, figsize=(20,15))
plt.show()
_images/Projekt_78_0.png
fig = px.histogram(AutoDF, x="Preis",title="Distribution over price (Euro)")
pyo.iplot(fig)

Untersuchung der numerischen Variablen

Um eine erste Übersicht über mögliche Zusammenhänge zwischen den verschiedenen Variablen zu erhalten, wird zunächst ein Pairplot erstellt. Um dn Plot übersichtlich zu halten, werden Variablen ausgewählt, zwischen denen bereits Korrelation vermutet wird.

sns.pairplot(data=AutoDF, vars=["Preis","PS","km","Verbrauch_l_pro_100km","Emissionen_g_pro_km"], hue="Kraftstoff",)
<seaborn.axisgrid.PairGrid at 0x28d1829ebe0>
_images/Projekt_82_1.png
sns.lmplot(data=AutoDF, x='PS', y='Preis')
<seaborn.axisgrid.FacetGrid at 0x2217511eee0>
_images/Projekt_83_1.png

Tatsächlich können im Pairplot Zusammenhänge zwischen einzelnen Variablen erkannt werden. Vor allem die starke Korrelation zwischen Verbrauch und Emissionen fällt im Plot auf, ist allerdings selbstverständlich da mit höherem Verbrauch in der Regel auch mehr Emissionen erzeugt werden. Doch auch weniger starke Abhängigkeiten von bspw. PS auf Preis können erkannt werden.

Nach der optischen Darstellung sollen nun im nächsten Schritt die Abhängigkeiten noch einmal in Zahlen dargestellt werden.

corr = AutoDF.corr()
corr['Preis'].sort_values(ascending=False)
Preis                    1.000000
PS                       0.638727
Emissionen_g_pro_km      0.417156
Verbrauch_l_pro_100km    0.414372
Erstzulassung            0.063967
Einparkhilfe            -0.035926
Leasing                 -0.058178
Navigationssystem       -0.063409
Sitzheizung             -0.084809
Klimaanlage             -0.114547
Alufelgen               -0.150819
km                      -0.339976
Name: Preis, dtype: float64
# Create correlation matrix for numerical variables
corr_matrix = AutoDF.corr()
corr_matrix
Preis Leasing km Erstzulassung PS Verbrauch_l_pro_100km Emissionen_g_pro_km Alufelgen Sitzheizung Klimaanlage Einparkhilfe Navigationssystem
Preis 1.000000 -0.058178 -0.339976 0.063967 0.638727 0.414372 0.417156 -0.150819 -0.084809 -0.114547 -0.035926 -0.063409
Leasing -0.058178 1.000000 -0.025905 0.066041 -0.040683 -0.059894 -0.064324 -0.005368 0.055004 0.102760 -0.000073 0.018808
km -0.339976 -0.025905 1.000000 -0.158512 -0.069001 0.092129 0.124874 0.073435 -0.011293 0.005921 -0.074650 -0.018828
Erstzulassung 0.063967 0.066041 -0.158512 1.000000 0.190821 -0.269409 -0.254416 0.025535 0.206469 0.127959 0.272622 0.271829
PS 0.638727 -0.040683 -0.069001 0.190821 1.000000 0.652536 0.644422 -0.164769 -0.020136 -0.134800 0.023753 0.061894
Verbrauch_l_pro_100km 0.414372 -0.059894 0.092129 -0.269409 0.652536 1.000000 0.984834 -0.038358 -0.121253 -0.118479 -0.175432 -0.136112
Emissionen_g_pro_km 0.417156 -0.064324 0.124874 -0.254416 0.644422 0.984834 1.000000 -0.035263 -0.120236 -0.111865 -0.174386 -0.133477
Alufelgen -0.150819 -0.005368 0.073435 0.025535 -0.164769 -0.038358 -0.035263 1.000000 0.076953 0.181066 0.071659 0.090605
Sitzheizung -0.084809 0.055004 -0.011293 0.206469 -0.020136 -0.121253 -0.120236 0.076953 1.000000 0.062076 0.149010 0.272942
Klimaanlage -0.114547 0.102760 0.005921 0.127959 -0.134800 -0.118479 -0.111865 0.181066 0.062076 1.000000 0.022308 0.044652
Einparkhilfe -0.035926 -0.000073 -0.074650 0.272622 0.023753 -0.175432 -0.174386 0.071659 0.149010 0.022308 1.000000 0.253472
Navigationssystem -0.063409 0.018808 -0.018828 0.271829 0.061894 -0.136112 -0.133477 0.090605 0.272942 0.044652 0.253472 1.000000
# Erstellen einer Heatmap um Abhängigkeiten zwischen den verschiedenen Variablen zu visualisieren

# Use a mask to plot only part of a matrix
mask = np.zeros_like(corr_matrix)
mask[np.triu_indices_from(mask)]= True

# Erstellen der Heatmap mit zusätzlichen Parametern
plt.subplots(figsize=(11, 15))
heatmap = sns.heatmap(corr_matrix, 
                      mask = mask, 
                      square = True, 
                      linewidths = .5,
                      cmap = 'coolwarm',
                      cbar_kws = {'shrink': .6,
                                'ticks' : [-1, -.5, 0, 0.5, 1]},
                      vmin = -1,
                      vmax = 1,
                      annot = True,
                      annot_kws = {"size": 10})
_images/Projekt_87_0.png
sns.boxenplot(data=AutoDF, x="Preis", y="Marke", orient="h", width=2)
<AxesSubplot:xlabel='Preis', ylabel='Marke'>
_images/Projekt_88_1.png

was macht sorted_nob ????

sorted_nb = AutoDF.groupby(['Marke'])['Preis'].median().sort_values()
sorted_nb
Marke
smart              5470.0
Fiat               5500.0
Suzuki             5890.0
Toyota             9990.0
Honda             10240.0
Nissan            10590.0
SsangYong         10980.0
MINI              11850.0
Opel              11900.0
Subaru            11990.0
Alfa              12880.0
Mitsubishi        12890.0
Cadillac          12990.0
Renault           13880.0
BMW               14990.0
Saab              14990.0
Volvo             15300.0
Mazda             15990.0
Volkswagen        16490.0
Lexus             16990.0
Ford              18890.0
SEAT              19330.0
Citroen           19970.0
Peugeot           19990.0
Kia               20990.0
Audi              21990.0
Hyundai           22980.0
Skoda             22990.0
Mercedes-Benz     23400.0
Jeep              23990.0
Cupra             24499.0
MG                27950.0
Jaguar            39980.0
Chevrolet         40990.0
Sonstige          45899.0
Porsche           48990.0
Land              49999.0
Alpina            52990.0
Dodge             55800.0
Aston            119900.0
Ferrari          139945.0
Name: Preis, dtype: float64
sns.boxplot(x=AutoDF['Marke'], y=AutoDF['Preis'], order=list(sorted_nb.index))
<AxesSubplot:xlabel='Marke', ylabel='Preis'>
_images/Projekt_91_1.png

Untersuchung der kategorialen Features

Untersuchung der Features “Ausstattung”

Als nächstes soll untersucht werden, inwiefern die Ausstattungsmerkmal einen eindeutigen Einfluss auf den Preis haben.

Austtattung=['Klimaanlage','Alufelgen','Sitzheizung','Einparkhilfe','Navigationssystem']
Austtattung
['Klimaanlage',
 'Alufelgen',
 'Sitzheizung',
 'Einparkhilfe',
 'Navigationssystem']
fig, ax = plt.subplots(2, 3, figsize=(15, 10))
for var, subplot in zip(Austtattung, ax.flatten()):
    sns.boxplot(x=var, y='Preis', data=AutoDF, ax=subplot)
_images/Projekt_96_0.png

Fazit: Keine`??

Untersuchung der Features Kraftstoff, Getriebe

PriceAveragePerKraftstoff=AutoDF.groupby(by="Kraftstoff")["Preis"].mean()
PriceAveragePerKraftstoff.plot(kind="bar",figsize=(12,6),color="m",title="Average Price per Kraftstoff")
<AxesSubplot:title={'center':'Average Price per Kraftstoff'}, xlabel='Kraftstoff'>
_images/Projekt_99_1.png
sns.stripplot(data=AutoDF, x="Kraftstoff", y="Preis" , size=3 )
<AxesSubplot:xlabel='Kraftstoff', ylabel='Preis'>
_images/Projekt_100_1.png
Diesel=AutoDF[AutoDF["Kraftstoff"]=="Diesel"]
Benzin=AutoDF[AutoDF["Kraftstoff"]=="Benzin"]
Elektro=AutoDF[AutoDF["Kraftstoff"]=="Elektro"]
Diesel
car version subtitle price leasing km Erstzulassung PS Zustand Fahrzeughalter ... Emissionen_g_pro_km Marke city PLZ country Alufelgen Sitzheizung Klimaanlage Einparkhilfe Navigationssystem
846 Mitsubishi Pajero 2800 TD GLS Panorama+7 Sitzer+long+AHK NaN 12890 0.0 202000 1994.0 125 Gebraucht 1 ... 297 Mitsubishi Duisburg 47249 DE False False False False False
1008 Volkswagen T4 Transporter Pritsche Doppelkabine 1.9 D *PLANE... NaN 3499 0.0 215983 1994.0 60 Gebraucht 2 ... 198 Volkswagen Ilm 85276 DE False False False False False
1140 Volkswagen T4 Multivan 2.5TDI Allstar NaN 9999 0.0 425000 1996.0 102 Gebraucht 3 ... 232 Volkswagen Weißenhorn 89264 DE False False False False False
1237 Mitsubishi Pajero 2800 TD GLS Panorama+7 Sitzer+long+AHK NaN 12890 0.0 202000 1994.0 125 Gebraucht 1 ... 297 Mitsubishi Duisburg 47249 DE False False False False False
1424 Volkswagen T4 Transporter Pritsche Doppelkabine 1.9 D *PLANE... NaN 3499 0.0 215983 1994.0 60 Gebraucht 2 ... 198 Volkswagen Ilm 85276 DE False False False False False
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
6063 Volkswagen Caddy 2.0 TDI DSG 4Motion Xenon*Standh*ACC*Navi Allrad, Schiebetür rechts, Navigationssystem, ... 24990 0.0 112703 2016.0 150 Gebraucht 1 ... 146 Volkswagen Dresden 01139 DE True True False False True
6067 Audi A6 3.0 TDI competition quattro Navi/Leder/Temp/ Sitzheizung, Allrad, Sportpaket, Zentralverrie... 35490 0.0 112000 2017.0 326 Gebraucht NaN ... 164 Audi Braunschweig 38110 DE False True True True False
6069 Audi A3 Sportback Sport 2.0 TDI quattro S-tronic Klima Sportsitze, Multifunktionslenkrad, Kopfairbag,... 18980 0.0 131800 2016.0 184 Gebraucht 1 ... 133 Audi Reichenhall 83435 DE False False False True False
6076 Skoda Superb Combi 2.0 TDI Ambition AHK Navi Anhängerkupplung, Navigationssystem, Dachrelin... 23890 0.0 48658 2019.0 150 Gebraucht 1 ... 114 Skoda Stuttgart 70565 DE True False False True True
6080 Skoda Kamiq 1.6TDI DSG Ambition*Vill/LED*SmartLink*17Zoll* Sitzheizung, Schlüssellose Zentralverriegelung... 24950 0.0 35000 2020.0 116 Gebraucht 1 ... 112 Skoda found NaN True True False True False

409 rows × 23 columns

npDiesel = Diesel["Preis"]
npBenzin = Benzin["Preis"]
#npElektro = Elektro["price"]
data = [npDiesel.values, npBenzin.values]
#data = [npDiesel.values, npBenzin.values, npElektro.values]

group_labels = ['Diesel', 'Benzin']
#group_labels = ['Diesel', 'Benzin', 'Elektro']
colors = ['#462EDE', '#DE2EBE', '#FF8033']

# Create distplot with curve_type set to 'normal'
fig = ff.create_distplot(data, group_labels, colors=colors,
                         bin_size=3000, show_rug=False)

# Add title
fig.update_layout(title_text='Hist and Curve Plot')
pyo.iplot(fig)
fig=px.scatter(AutoDF,x="PS",y="Preis",color="Emissionen_g_pro_km",size="Verbrauch_l_pro_100km",
              hover_data=["Marke","Titel","Kraftstoff"],title="Price over PS",
              trendline="ols")
pyo.iplot(fig)

Kartenvisualisierung

Als nächstes werden wird der Standort der zum Verkauf angebotenen Fahrzeuge in einer Landkarte visualisiert.
Für diese Zwecke wurde beim Webcrawling das Attribut Location von Autoscout24 abgezogen und anschließend in der Datenaufbereitung der Stadtname und das Land als extra Spalte angelegt.
Mithilfe des Geolocators werden jeder Stadt Longitude und Latitude zugeordnet und im Dataframe geoDF gespeichert. Dieses Dataframe wird anschließend über den Index mit dem AutoDF gejoined.

geolocator = Nominatim(user_agent="my_app")
geoDF = pd.DataFrame()
for city in AutoDF.index:
    try:
        location = geolocator.geocode(AutoDF['Stadt'][city])
        geoDF = geoDF.append({"longitude": location.longitude, "latitude": location.latitude}, ignore_index=True)  
    except:
        geoDF = geoDF.append({"longitude": None, "latitude": None}, ignore_index=True)
geoDF
#Index von AutoDF zurücksetzen, da aufgrund der Entfernung der Null-Values bei Verbrauch und Emissionen viele Zeilen weggefallen sind
#sonst kann nicht mit GeoDF gejoined werden
AutoDF = AutoDF.reset_index(drop=True)

#Join von GeoDF und AutoDF über Index
AutoDF = pd.merge(AutoDF, geoDF, left_index=True, right_index=True)

Unter Verwendung von Longitude und Latitude werden die Fahrzeugstandorte auf einer Folium Map visualisiert.
Zusätzlich wird jedem Datenpunkt eine Pop-Up Beschreibung hingefügt, welche Stadtname, Autobeschreibung und Preis beinhaltet.

AutoDF
car version subtitle price leasing location km Erstzulassung PS Zustand ... city PLZ country Alufelgen Sitzheizung Klimaanlage Einparkhilfe Navigationssystem longitude latitude
0 Citroen 2CV 2 CV 6 0,6 Club Cabrio NaN 19970 0.0 Verkaufsteam Neuensalz • DE-08541 Neuensalz be... 50704 1987 27 Gebraucht ... Plauen 08541 DE False False False False False 12.134652 50.495063
1 Citroen 2CV 6 0,6 Club Cabrio 20 kW (27 PS), Schaltgetriebe NaN 22570 0.0 David Meßmer • DE-85614 Kirchseon 50704 1987 27 Gebraucht ... Kirchseon 85614 DE False False False False False NaN NaN
2 Sonstige Marken ANDERE RMC Roadster 1950 Linkslenker NaN 45899 0.0 Andreas Astaller • DE-84069 Schierling 40854 1950 101 Gebraucht ... Schierling 84069 DE False False False False False 12.137863 48.835088
3 Ford Fiesta Sammlerfahrzeug top gepflegt NaN 9990 0.0 Armin Jungkeit • DE-79108 Freiburg 47898 1980 53 Gebraucht ... Freiburg 79108 DE False False False False False 7.849400 47.996090
4 BMW 316 BAUR Cabrio mit geringer Laufleistung NaN 11980 0.0 John Klass • DE-58285 Gevelsberg 129301 1987 90 Gebraucht ... Gevelsberg 58285 DE False False False False False 7.340479 51.320742
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1668 Audi RS6 PERFORMANCE V-MAX OFFEN MATT 360*CAM NaN 66399 0.0 Herr Beltekoglu • DE-73084 Salach 90000 2017 605 Gebraucht ... Salach 73084 DE False False False False False 9.739514 48.690408
1669 Skoda Kamiq 1.6TDI DSG Ambition*Vill/LED*SmartLink*17Zoll* Sitzheizung, Schlüssellose Zentralverriegelung... 24950 0.0 not found 35000 2020 116 Gebraucht ... found NaN True True False True False -122.384327 47.667539
1670 Jaguar F-Type P380 S AWD Leder Navi Kamera BR-Green Elektrische Heckklappe, Wegfahrsperre, Einpark... 58925 0.0 Bernd Wagner • DE-15517 Fürstenwalde/Spree 26500 2016 381 Gebraucht ... Fürstenwalde/Spree 15517 DE False False False True False 14.064985 52.358021
1671 BMW 125 i Advantage/17"/Klima/PDC/Sitzheiz Sportfahrwerk, Sitzheizung, Zentralverriegelun... 17590 0.0 Ihr Hermann Menton Verlkausteam • DE-72072 Tüb... 83422 2015 218 Gebraucht ... Tübingen 72072 DE False True True False False 9.053553 48.523616
1672 Mercedes-Benz A 250 Progressive LED Navi Licht&Sicht Klimaautomatik, LED-Scheinwerfer, Navigationss... 25990 0.0 Ihr Rosier Team • DE-38122 Braunschweig 95768 2018 224 Gebraucht ... Braunschweig 38122 DE False False True False True 10.523607 52.264658

1673 rows × 26 columns

m = folium.Map([50.0 , 10.0],zoom_start=4)
for i in AutoDF.index:
    try:
        folium.Marker( location=[ AutoDF['latitude'][i], AutoDF['longitude'][i] ], popup = [AutoDF['Stadt'][i], AutoDF['Titel'][i], AutoDF['Preis'][i]]).add_to(m)
    except:
        Continue
m
Make this Notebook Trusted to load map: File -> Trust Notebook